Skip to content

fix[venom]: check operand position in mem2var promotion#5085

Open
banteg wants to merge 3 commits into
vyperlang:masterfrom
banteg:fix/mem2var-operand-position
Open

fix[venom]: check operand position in mem2var promotion#5085
banteg wants to merge 3 commits into
vyperlang:masterfrom
banteg:fix/mem2var-operand-position

Conversation

@banteg

@banteg banteg commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What I did

Fixes #5070.

Mem2Var decided whether an alloca is promotable by looking only at the opcodes of its uses, not the operand position. An alloca used as the value stored by an mstore (i.e. a pointer escaping into memory, mstore %b, %a) was mistaken for a memory-slot access and promoted, silently deleting the store of the pointer value.

How I did it

Added an _is_pointer_use check requiring every use to place the alloca in the memory-address operand position: mload (single operand, always the address) is fine; for mstore (operands [value, ptr]) and return (operands [size, ptr]), the alloca must not appear in operands[0]. This also blocks the self-referential mstore %a, %a shape. Operand-order semantics confirmed against memory_location.py and load_elimination.py (venom operands are reversed relative to assembly).

How to verify it

New tests/unit/compiler/venom/test_mem2var.py: the issue reproducer asserts mstore %b, %a survives MakeSSA+Mem2Var (fails on master, where the store is deleted), plus a positive case asserting ordinary promotion still happens. Full tests/unit/compiler/ passes.

Commit message

Mem2Var decided promotability by checking only the opcodes of an
alloca's uses (`mstore`/`mload`/`return`). an alloca appearing as the
*value* operand of an mstore -- i.e. a pointer being stored into
another memory location -- was therefore treated as a promotable
memory-slot access, and promotion deleted the store of the pointer
value.

require every use to place the alloca in the memory-address operand
position (mstore/return operands are [value/size, ptr]); a use in the
value/size position is an escape and blocks promotion.

Description for the changelog

Fix: Venom Mem2Var no longer promotes allocas whose pointer value escapes as the stored value of an mstore.

Cute Animal Picture

cute animal

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: befec1ca7b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +69 to 70
if not all2(self._is_pointer_use(inst, alloca_inst.output) for inst in uses):
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve escaping uses before promoting other allocas

When the destination alloca is visited before the source alloca, this per-alloca position check is order-dependent: for %b = alloca 32; %a = alloca 32; mstore %b, %a, %b passes this check as the address operand and line 86 rewrites the mstore away before %a is examined. %a then no longer has its value-operand escape in the DFG and can still be promoted/deleted, so the issue remains for allocas declared after their destination slot. The escape set needs to be determined from the original uses before mutating stores, or stores of any alloca pointer should block promotion that would remove them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified empirically — the order-swapped shape is handled correctly. With %b visited first:

%b = alloca 32
%a = alloca 32
mstore %b, %a
%x = mload %a
%y = mload %b
sink %x, %y

promoting %b rewrites the mstore to %alloca_b_0 = %a via InstUpdater, which maintains the DFG — so when %a is examined, its uses are [assign, mload], and the assign opcode fails _is_pointer_use, blocking promotion. Output after MakeSSA+Mem2Var:

%b = alloca 32
%a = alloca 32
%alloca_b_0 = %a
%x = mload %a
%y = %alloca_b_0
sink %x, %y

%a survives as a real allocation with a real load, and the pointer value flows into %b's replacement variable — which is exactly the promotion semantics for %b (its slot held the pointer value). Note the escape check exists to prevent the pointer bytes from being silently dropped, not to prevent the destination slot from being promoted; once the destination is a stack variable, the stored pointer value is preserved in SSA.

Added test_mem2var_stored_pointer_dest_promoted_first (722a274) pinning this shape.

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.94%. Comparing base (242a4fa) to head (722a274).
⚠️ Report is 17 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #5085   +/-   ##
=======================================
  Coverage   92.93%   92.94%           
=======================================
  Files         188      188           
  Lines       27840    27848    +8     
  Branches     4831     4833    +2     
=======================================
+ Hits        25874    25882    +8     
  Misses       1315     1315           
  Partials      651      651           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread vyper/venom/passes/mem2var.py

@charles-cooper charles-cooper left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, paging @harkal and @HodanPlodky for review

@github-actions

Copy link
Copy Markdown

Gas Changes

No changes detected.

Summary

  • Total tests measured: 815
  • Changed: 0
  • Regressions (gas up): 0
  • Improvements (gas down): 0
  • New tests: 0
  • Deleted tests: 0
  • Newly failing: 0
  • Newly passing: 0

@github-actions

Copy link
Copy Markdown

📊 Bytecode Size Changes (venom)

No changes detected.

Full bytecode sizes

Contract legacy-O2 legacy-Os -O2 -O3 -Os
curvefi/amm/stableswap/meta_implementation/meta_implementation_v_700.vy 23610 22805 20786 19755 19315
curvefi/legacy/CurveStableSwapMetaNG.vy 24952 23578 20490 19871 19175
curvefi/amm/stableswap/implementation/implementation_v_700.vy 24962 23769 20264 19393 18845
curvefi/legacy/CurveStableSwapNG.vy 24473 23298 19677 18844 18314
curvefi/amm/tricryptoswap/implementation/implementation_v_200.vy 20724 19959 18020 17518 16961
yearnfi/VaultV3.vy 19972 19063 17017 15131 14477
curvefi/amm/twocryptoswap/implementation/implementation_v_210.vy 17634 16894 15685 15132 14648
curvefi/legacy/CurveCryptoSwap2.vy 18947 18382 15634 15092 14711
yearnfi/VaultV2.vy 16676 15763 13863 13405 12574
curvefi/amm/stableswap/factory/factory_v_100.vy 14558 13978 13317 11825 11788
curvefi/gauge/child_gauge/implementation/implementation_v_110.vy 12338 11561 10270 9775 9182
curvefi/gauge/child_gauge/implementation/implementation_v_100.vy 12017 11249 9998 9502 8920
curvefi/amm/stableswap/views/views_v_120.vy 12784 12368 9970 9413 9532
curvefi/amm/tricryptoswap/math/math_v_200.vy 11189 11126 9520 8162 8424
curvefi/legacy/CurveCryptoMathOptimized3.vy 11188 11125 9519 8162 8424
curvefi/gauge/child_gauge/implementation/implementation_v_020.vy 10665 9947 9013 8565 8028
curvefi/helpers/router/router_v_110.vy 6717 6717 7003 6376 6607
curvefi/amm/tricryptoswap/views/views_v_200.vy 7821 7776 6697 6445 6514
curvefi/registries/metaregistry/metaregistry_v_110.vy 7590 6732 6651 5888 5727
curvefi/helpers/stable_swap_meta_zap/stable_swap_meta_zap_v_100.vy 7302 7067 6379 6012 6114
curvefi/amm/twocryptoswap/views/views_v_200.vy 6991 6946 6272 6026 6089
curvefi/amm/twocryptoswap/factory/factory_v_200.vy 5540 5252 5994 4697 4845
curvefi/amm/tricryptoswap/factory/factory_v_200.vy 5246 5021 5923 4926 5039
curvefi/registries/metaregistry/registry_handlers/stableswap/handler_v_110.vy 6633 6259 5859 5094 5562
curvefi/amm/twocryptoswap/math/math_v_210.vy 6800 6800 5581 5107 5112
curvefi/gauge/child_gauge/factory/factory_v_201.vy 4844 4547 4266 4014 3780
yearnfi/VaultFactory.vy 3765 3617 3985 2505 2965
curvefi/registries/metaregistry/registry_handlers/tricryptoswap/handler_v_110.vy 4241 3939 3838 3547 3547
curvefi/registries/metaregistry/registry_handlers/twocryptoswap/handler_v_110.vy 4186 3884 3777 3417 3433
curvefi/gauge/child_gauge/factory/factory_v_100.vy 4183 3914 3694 3428 3213
curvefi/helpers/rate_provider/rate_provider_v_101.vy 3260 3260 2779 2437 2450
curvefi/registries/address_provider/address_provider_v_201.vy 2973 2782 2713 2569 2424
curvefi/amm/stableswap/math/math_v_100.vy 3067 3046 2598 2403 2423
curvefi/helpers/rate_provider/rate_provider_v_100.vy 2847 2841 2357 2050 2058
curvefi/helpers/deposit_and_stake_zap/deposit_and_stake_zap_v_100.vy 2322 2316 2123 1889 1921
curvefi/governance/relayer/taiko/relayer_v_001.vy 2068 2064 1784 1579 1612
curvefi/governance/relayer/polygon_cdk/relayer_v_101.vy 1556 1523 1587 1405 1406
curvefi/governance/relayer/arb_orbit/relayer_v_101.vy 1266 1262 1280 1124 1155
curvefi/governance/relayer/op_stack/relayer_v_101.vy 1186 1182 1219 1066 1094
curvefi/governance/relayer/not_rollup/relayer_v_100.vy 1168 1153 1208 1061 1073
curvefi/governance/vault/vault_v_100.vy 964 941 885 866 864
curvefi/governance/relayer/relayer_v_100.vy 496 496 600 505 510
curvefi/governance/agent/agent_v_100.vy 541 541 443 415 419
curvefi/governance/agent/agent_v_101.vy 541 541 443 415 419

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mem2Var promotes allocas used as stored pointer values

3 participants